/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simulation;

import java.util.List;
import logging.LogSetup;
import lpsolve.LpSolve;
import lpsolve.LpSolveException;
import org.apache.log4j.Logger;

/**
 *
 * @author Danielondon
 */
public class LPSolver implements ISolver{
    protected Logger logger = LogSetup.getLogger();
    int slotCount;
    double []prices;
    int [] connected;
    double [] requiredConsumption;
    //double minCharge;
    double maxCharge;
    List<int[]> patterns;
    private String name;
    
    public LPSolver(String name, int slotCount, double []prices, int [] connected, 
            List<int[]> patterns, double[] requiredConsumption, double maxCharge) throws Exception{
        this.name = name;
        this.slotCount = slotCount;
        this.prices = prices; 
        this.connected = connected;
        this.requiredConsumption = requiredConsumption;
        //this.minCharge =minCharge;
        this.maxCharge = maxCharge; 
        this.patterns = patterns;
        
        if (prices.length != slotCount || connected.length != slotCount) {
            throw new Exception ("Invalid dimentsion of prices or connected arrays.");
        }
        if (patterns.size() != requiredConsumption.length) {
            throw new Exception ("Invalid dimension of required consumption or driving patterns.");
        }
    }
    
    @Override
    public double[] solve() throws LpSolveException, Exception{
        // Rows : Constraints, Columss: variables
        LpSolve problem = LpSolve.makeLp(this.patterns.size(), this.slotCount);
        
        for (int i =1 ; i <= this.patterns.size(); i++){
            int [] pattern = this.patterns.get(i-1);
            String constraint = this.getConstraintFormatted(pattern);
            problem.strAddConstraint(constraint, LpSolve.EQ, this.requiredConsumption[i-1]);
        }
        
        for (int i =1; i <= slotCount; i++){
            problem.setLowbo(i, 0);
            if (this.connected[i-1] == CommonResources.CONNECTED)
                problem.setUpbo(i, this.maxCharge);
            else
                problem.setUpbo(i, 0);
        }
        
        String objective = this.getObjective(this.prices, this.connected);
        problem.strSetObjFn(objective);
        int response = problem.solve();
        
         // print solution
        logger.info("Value of objective function: " + problem.getObjective());
        double[] var = problem.getPtrVariables();
        //for (int i = 0; i < var.length; i++) {
        //  logger.info("Value of var[" + i + "] = " + var[i]);
        //}
        // delete the problem and free memory
        problem.deleteLp();        
        
        if(response != lpsolve.LpSolve.OPTIMAL)
            throw new Exception("No Optimal Solution founded");
        return var;
    }
    
    private double[] getSolution() {
        double [] solution = new double[1];
        
        return solution;
    }

    private String getConstraintFormatted(int[] pattern) {
        String result = "";
        for (int i = 0; i < pattern.length - 1; i++){
            result+= pattern[i] + " ";
        }
        result += pattern[pattern.length - 1];
        
        return result;
    }

    private String getObjective(double [] prices, int [] connected) {
        String result = "";
        for (int i = 0; i < prices.length - 1; i++){
            result+= prices[i]*(double)connected[i] + " ";
        }
        result +=  prices[prices.length-1]*(double)connected[connected.length-1];
        
        return result;
    }
}
